home *** CD-ROM | disk | FTP | other *** search
- {
- Original module in C is
- Copyright (c) 1986,1992 by Borland International Inc.
- All Rights Reserved.
- %% port to BPASCAL and enhancements by Juancarlo Anez
- %% CIS id [73000,1064]
- %% date 92.04.08
- }
- UNIT GETOPT2_;
- INTERFACE
-
- CONST
- MaxArgs = 50; { Maximun number of comandline arguments }
- MaxCmdLin = 255; { Maximun comandline lenth }
- EOFch = #24; { returned by getOpt when no more options }
- NONOPTch = '√'; { returned by getOpt when arg is non-option}
- ERRORch = #1;
- opterr :Boolean = FALSE; { allow error message }
-
- optind :Integer = 1; { index of which argument is next }
- optarg :pChar = nil; { pointer to argument of current option }
- argc :Integer = 0; { count of non-opt arguments when
- getOpt has returned EOFch }
- VAR
- argv :array[0..MaxArgs] of pChar; { non-opt arguments }
-
- TYPE
- tCharSet = set of succ(' ')..#126;
-
- function getopt(argOpts : pChar):Char;
-
- {
- Parse the command line options
-
- The original standard option syntax is:
-
- option ::= SW [optLetter]* [argLetter space* argument]
-
- %%% 92.04.08 -- Juancarlo Anez, CIS 73000,1064
- It has been augmented to:
-
- option ::= SW ([optLetter]* [argLetter space* argument])*
-
- In ohter words, options and non-options may be interplaced.
- Additionaly, after getOpt returns EOFch, argv[] will point only to
- non-options and argc will be the exact count of them
- %%%
-
- where
- - SW is either '/' or '-', according to the current setting
- of the MSDOS switchar (int 21h function 37h).
- - there is no space before any optLetter or argLetter.
- - opt/arg letters are alphabetic, not punctuation characters.
- - argLetters, if present, are found in the argOpts set.
- - argument is any white-space delimited string. Note that it
- can include the SW character.
- - upper and lower case letters are distinct.
-
- There may be multiple option clusters on a command line, each
- beginning with a SW, but all must appear before any non-option
- arguments (arguments not introduced by SW). Opt/arg letters may
- be repeated: it is up to the caller to decide if that is an error.
-
- The character SW appearing alone as the last argument is an error.
- The lead-in sequence SWSW ("--" or "//") causes itself and all the
- rest of the line to be ignored (allowing non-options which begin
- with the switch char).
-
- The set ArgOpts allows valid arg letters to be recognized.
- Getopt () returns the value of the option character found, or
- EOF if no more options are in the command line. If option is an
- argLetter then the global optarg is set to point to the argument
- string (having skipped any white-space).
-
- The global optind is initially 1 and is always left as the index
- of the next argument of argv[] which getopt has not taken. Note
- that if "--" or "//" are used then optind is stepped to the next
- argument before getopt() returns EOF.
-
- If an error occurs, that is an SW char precedes an unknown letter,
- then getopt() will return a '?' character and normally prints an
- error message via perror(). If the global variable opterr is set
- to false (zero) before calling getopt() then the error message is
- not printed.
-
- For example, if the MSDOS switch char is '/' (the MSDOS norm) and
-
- argOpts == 'AFUZ';
-
- then 'P', 'u', 'w', and 'X' are option letters and 'F', 'U', 'Z'
- are followed by arguments. A valid command line may be:
-
- aCommand /uPFPi /X /A L someFile
-
- where:
- - 'u' and 'P' will be returned as isolated option letters.
- - 'F' will return with "Pi" as its argument string.
- - 'X' is an isolated option.
- - 'A' will return with "L" as its argument.
- - "someFile" is not an option, and terminates getOpt. The
- caller may collect remaining arguments using argv pointers.
- }
-
-
-
- IMPLEMENTATION
- USES
- WINDOS,
- STRINGS;
-
- CONST
- letP :pChar = nil; { remember next option char's location }
- SW :Char = #0; { DOS switch character, either '-' or '/' }
- VAR
- cmdlin :array[0..MaxCmdLin] of Char;
-
- { delete an already processed option from argv }
- procedure compressArgs(i :Integer);
- begin
- while i < argc
- do begin
- argv[i] := argv[i+1];
- inc(i)
- end;
- argv[argc] := nil;
- dec(argc)
- end;
-
- { initialization, determine argc and argv
- using the parsing already done by WINDOS unit
- }
- procedure init;
- var
- i :Integer;
- pos :pChar;
- regs :TRegisters;
- begin
- { get SW using dos call 0x37 }
- regs.AX := $3700;
- msDOS(regs);
- SW := Char(regs.DL);
- argc := getArgCount;
- pos := cmdlin;
- for i := 0 to argc
- do begin
- argv[i] := pos;
- getArgStr(pos, i, 512-(pos-cmdlin));
- pos := strEnd(pos);
- inc(pos);
- end;
- pos^ := #0;
- for i := argc+1 to MaxArgs
- do
- argv[i] := nil;
- end;
-
- function getopt(argOpts : pChar):Char;
- label
- gopERROR;
- var
- ch :array[0..1] of Char;
- optP :pChar;
- begin
- if (SW = #0)
- then
- init;
-
- ch[0] := EOFch;
- ch[1] := #0;
- optarg := nil;
- while (optind <= argc)
- do begin
- if (letP = nil) then begin
- letP := argv[optind];
- if (letP = nil) then break;
- if not (letP^ in [SW,'-','/'])then begin
- optArg := letP;
- letP := nil;
- ch[0] := NONOPTch;
- inc(optind);
- break
- end;
- compressArgs(optind);
- inc(letP);
- if letP^ in [SW,'-','/'] then begin
- letP := nil;
- optind := argc+1;
- break;
- end
- end;
- ch[0] := letP^;
- if ch[0] = #0 then goto gopError;
- optP := strPos(argOpts, ch);
- inc(letP);
- if (optP <> nil)
- then begin
- if (letP^ = #0)
- then begin
- if (optind >= argc) then goto gopError;
- letP := argv[optind];
- compressArgs(optind)
- end;
- optarg := letP;
- letP := nil;
- end
- else begin
- if (letP^ = #0)
- then begin
- letP := nil
- end;
- optarg := nil;
- end;
- break
- end;
- getopt := ch[0];
- exit;
-
- gopError:
- if (opterr)
- then begin
- writeln(output,'Unknown switch ',SW,ch[0]);
- halt(1)
- end;
- optarg := letP;
- getopt := ERRORch;
- letP := nil;
- exit;
- end;
- END.